﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace SQLite
{
    internal static class AttributeHelper
    {
        /// <summary>
        /// 表名缓存
        /// </summary>
        private static readonly Dictionary<string, KeyValuePair<TableAttribute, List<ColumnAttribute>>> _TableCache = new Dictionary<string, KeyValuePair<TableAttribute, List<ColumnAttribute>>>();

        /// <summary>
        /// 获取表特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static TableAttribute GetTableAttribute<T>(this T t) where T : class => t.GetType().GetTableAttribute();


        /// <summary>
        /// 获取表特性
        /// </summary>
        /// <typeparam name="type"></typeparam>
        /// <returns></returns>
        public static TableAttribute GetTableAttribute(this Type type)
        {
            var attr = GetDbAttribute(type);
            if (attr.HasValue)
            {
                return attr.Value.Key;
            }
            else
            {
                var attribute = type.TypeToKeyValuePair();
                type.SetDbAttribute(attribute);
                return attribute.Key;
            }
        }

        /// <summary>
        /// 获取表特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<ColumnAttribute> GetColumnAttribute<T>(this T t) where T : class => t.GetType().GetColumnAttribute();


        /// <summary>
        /// 获取表特性
        /// </summary>
        /// <typeparam name="type"></typeparam>
        /// <returns></returns>
        public static List<ColumnAttribute> GetColumnAttribute(this Type type)
        {
            var attr = GetDbAttribute(type);
            if (attr.HasValue)
            {
                return attr.Value.Value;
            }
            else
            {
                var attribute = type.TypeToKeyValuePair();
                type.SetDbAttribute(attribute);
                return attribute.Value;
            }
        }


        /// <summary>
        /// 获取类型的自定义属性
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static KeyValuePair<TableAttribute, List<ColumnAttribute>> TypeToKeyValuePair(this Type type)
        {
            var table = type.GetCustomAttributes(false).FirstOrDefault(c => (c as TableAttribute) != null);
            if (table != null)
            {
                var tableAttribute = table as TableAttribute;
                var keyValuePair = new KeyValuePair<TableAttribute, List<ColumnAttribute>>(tableAttribute, new List<ColumnAttribute>());
                type.GetProperties().ToList()
                    .ForEach(c =>
                    {
                        var colm = c.GetCustomAttributes(false).FirstOrDefault() as ColumnAttribute;
                        if (colm != null)
                        {
                            if (string.IsNullOrWhiteSpace(colm.ColumnName.Trim()))
                            {
                                colm.ColumnName = c.Name;
                            }
                            colm.FileName = c.Name;
                            keyValuePair.Value.Add(colm);
                        }
                    });


                CheckAttribute(type, keyValuePair);
                return keyValuePair;
            }
            else
            {
                throw new ArgumentNullException($"未给{type.FullName}赋予[TableAttribute]特性.");
            }

        }


        /// <summary>
        /// 从缓存获取属性
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static KeyValuePair<TableAttribute, List<ColumnAttribute>>? GetDbAttribute(this Type type)
        {
            if (_TableCache.ContainsKey(type.GetCacheKey()))
            {
                return _TableCache[type.GetCacheKey()];
            }
            return null;
        }

        /// <summary>
        /// 验证特性
        /// </summary>
        /// <param name="value"></param>
        private static void CheckAttribute(Type type, KeyValuePair<TableAttribute, List<ColumnAttribute>> value)
        {
            if (!value.Value.Any())
            {
                throw new ArgumentNullException($"{type.FullName}没有任何列[ColumnAttribute]特性,无法关联表.");
            }
            var pkNumber = value.Value.Where(c => c.IsPk).Count();
            if (pkNumber < 1)
            {
                throw new InvalidOperationException($"{type.FullName}未指定主键.\r\n主键的个数有且紧有一个");
            }
            if (pkNumber > 1)
            {
                throw new InvalidOperationException($"{type.FullName}指定了多个主键.\r\n主键的个数有且紧有一个");
            }

        }


        /// <summary>
        /// 属性存入缓存
        /// </summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        private static void SetDbAttribute(this Type type, KeyValuePair<TableAttribute, List<ColumnAttribute>> value)
        {
            CheckAttribute(type, value);
            _TableCache[type.GetCacheKey()] = value;
        }

        /// <summary>
        /// 根据类型获取Key
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static string GetCacheKey(this Type type)
        {
            return $"{type.FullName}._TableAttributeKey";
        }


    }
}
